import 'dart:convert';
import 'dart:io';

import 'package:ceramics/util/ab_api.dart';
import 'package:ceramics/util/ab_log.dart';
import 'package:ceramics/util/ab_oss_fetch_util.dart';
import 'package:ceramics/widgets/ab_image.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:path_provider/path_provider.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:ceramics/extensions/ab_string_extensions.dart';

enum ShowImageType {
  thumb,
  middle,
  origin
}

class ImageCache {
  static final ImageCache _singleton = ImageCache._internal();
  factory ImageCache() {
    return _singleton;
  }
  ImageCache._internal();

  final _counter = 0.obs;

  Map<String,OSSResponse> ossCacheMap = {};

  static updateLocalCache(String key, OSSResponse response) async {
    ImageCache().ossCacheMap[key] = response;
    debounce(ImageCache()._counter, (callback) async {
      Log.i("updateLocalCache");
      await Future.delayed(const Duration(seconds: 1));
          var json = ImageCache().ossCacheMap.map((key, value) => MapEntry(key, value.toJson()));
      var docPath = await getApplicationDocumentsDirectory();
      var file = File("${docPath.path}/oss_image.json");
      file.writeAsString(jsonEncode(json));
    },time: const Duration(seconds: 1));
  }

  static initLocalCache() async {
    var docPath = await getApplicationDocumentsDirectory();
    var file = File("${docPath.path}/oss_image.json");
    if (file.existsSync()) {
      var json = jsonDecode(file.readAsStringSync()).cast<List<Map<String,dynamic>>>();
      ImageCache().ossCacheMap = json.map((e) => Map<String,dynamic>.from(e)).map((e) => MapEntry(e.keys.first,OSSResponse.fromJson(e.values.first))).cast<String,OSSResponse>().toMap();
    }
  }

}


class ABNetworkImage extends StatefulWidget {
  final String url;
  final ShowImageType type;
  final Widget? placeholder;
  final double? width;
  final double? height;
  const ABNetworkImage({super.key,required this.url,this.type = ShowImageType.thumb, this.placeholder
    ,this.width,this.height
  });

  @override
  State<ABNetworkImage> createState() => _ABNetworkImageState();
}

class _ABNetworkImageState extends State<ABNetworkImage> {

  String? _realImageURL;

  @override
  void initState() {
    super.initState();
    _fetchRealImage();
  }

  _fetchRealImage() async {
    var ossRes = ImageCache().ossCacheMap[widget.url];
    if (ossRes != null) {
      OssCaches.ossCaches.add(ossRes);
      OssCaches.updateToLocalCache();
      var imageURL = "";
      switch (widget.type) {
        case ShowImageType.thumb:
          imageURL = ImageCache().ossCacheMap[widget.url]!.thumbUrl;
          break;
        case ShowImageType.middle:
          imageURL = ImageCache().ossCacheMap[widget.url]!.middleThumbUrl;
          break;
        case ShowImageType.origin:
          imageURL = ImageCache().ossCacheMap[widget.url]!.mediaUrl;
          break;
      }
      if (!imageURL.isExpired()) {
        setState(() {
          _realImageURL = imageURL;
        });
        return;
      }
    }
    api.fetchOssURL([OSSRequest(widget.url, 'image')]).then((value) {
      ImageCache.updateLocalCache(widget.url,value.first);
      setState(() {
        switch (widget.type) {
          case ShowImageType.thumb:
            _realImageURL = value[0].thumbUrl;
            break;
          case ShowImageType.middle:
            _realImageURL = value[0].middleThumbUrl;
            break;
          case ShowImageType.origin:
            _realImageURL = value[0].mediaUrl;
            break;
        }
      });
    });
  }

  @override
  Widget build(BuildContext context) {
    var defaultPlaceholder = Container(
      width: widget.width,
      height: widget.height,
      color: Colors.grey,
    );
    return _realImageURL == null ? widget.placeholder ?? defaultPlaceholder : CachedNetworkImage(
      imageUrl: _realImageURL!,
      width: widget.width,
      height: widget.height,
      placeholder: (context, url) => widget.placeholder ?? defaultPlaceholder,
      errorWidget: (context, url, error) => const Icon(Icons.error),
    );
  }
}
